﻿namespace UnityEditorInternal
{
    using System;
    using System.IO;
    using System.Runtime.CompilerServices;
    using UnityEditor;
    using UnityEngine;

    public sealed class AnimatorController : UnityEngine.Object
    {
        private const string kControllerExtension = "controller";
        public static AnimatorController lastActiveController;
        public static int lastActiveLayerIndex;
        public System.Action OnAnimatorControllerDirty;

        public AnimatorController()
        {
            Internal_Create(this);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void AddEvent(string name, AnimatorControllerEventType type);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void AddLayer(string name);
        public static AnimatorController CreateAnimatorControllerAtPath(string path)
        {
            AnimatorController asset = new AnimatorController {
                name = Path.GetFileName(path)
            };
            StateMachine stateMachine = new StateMachine();
            asset.AddLayer("Base Layer");
            stateMachine.hideFlags = HideFlags.HideInHierarchy;
            asset.SetLayerStateMachine(0, stateMachine);
            stateMachine.name = asset.GetLayerName(0);
            AssetDatabase.CreateAsset(asset, path);
            AssetDatabase.AddObjectToAsset(stateMachine, asset);
            return asset;
        }

        public static AnimatorController CreateAnimatorControllerAtPathWithClip(string path, AnimationClip clip)
        {
            AnimatorController controller = CreateAnimatorControllerAtPath(path);
            controller.GetLayerStateMachine(0).AddState(clip.name).SetMotion(0, clip);
            return controller;
        }

        public static AnimatorController CreateAnimatorControllerForClip(AnimationClip clip)
        {
            string assetPath = AssetDatabase.GetAssetPath(clip);
            if (string.IsNullOrEmpty(assetPath))
            {
                return null;
            }
            string fullPath = Path.GetFullPath(FileUtil.DeleteLastPathNameComponent(assetPath));
            assetPath = FileUtil.GetProjectRelativePath(EditorUtility.SaveFilePanel("Create Animator Controller", fullPath, "NewController.controller", "controller"));
            if (string.IsNullOrEmpty(assetPath))
            {
                return null;
            }
            return CreateAnimatorControllerAtPathWithClip(assetPath, clip);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int FindEvent(string name);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern AnimatorController GetAnimatorController(Animator behavior);
        internal string GetDefaultBlendTreeEvent()
        {
            for (int i = 0; i < this.GetEventCount(); i++)
            {
                if (this.GetEventType(i) == 1)
                {
                    return this.GetEventName(i);
                }
            }
            return "Blend";
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetEventCount();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern bool GetEventDefaultBool(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern float GetEventDefaultFloat(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetEventDefaultInt(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern Vector3 GetEventDefaultVector(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern float GetEventMax(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern float GetEventMin(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern string GetEventName(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetEventType(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern AnimatorLayerBlendingMode GetLayerBlendingMode(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetLayerCount();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern AvatarBodyMask GetLayerHumanMask(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern bool GetLayerIKPass(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetLayerMotionSetIndex(int layerIndex);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern string GetLayerName(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern AvatarSkeletonMask GetLayerSkeletonMask(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern StateMachine GetLayerStateMachine(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetLayerSyncedIndex(int layerIndex);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern int GetLayerType(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        private static extern void INTERNAL_CALL_SetEventDefaultVector(AnimatorController self, int index, ref Vector3 value);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        private static extern void Internal_Create(AnimatorController mono);
        public static void OnInvalidateAnimatorController(AnimatorController controller)
        {
            if (controller.OnAnimatorControllerDirty != null)
            {
                controller.OnAnimatorControllerDirty();
            }
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void RemoveEvent(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void RemoveLayer(int index);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public static extern void SetAnimatorController(Animator behavior, AnimatorController controller);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetEventDefaultBool(int index, bool value);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetEventDefaultFloat(int index, float value);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetEventDefaultInt(int index, int value);
        public void SetEventDefaultVector(int index, Vector3 value)
        {
            INTERNAL_CALL_SetEventDefaultVector(this, index, ref value);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetEventName(int index, string name);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetEventType(int index, AnimatorControllerEventType type);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerBlendingMode(int index, AnimatorLayerBlendingMode mode);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerHumanMask(int index, AvatarBodyMask mask);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerIKPass(int index, bool ik);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerName(int index, string name);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerSkeletonMask(int index, AvatarSkeletonMask mask);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerStateMachine(int index, StateMachine stateMachine);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerSyncedIndex(int layerIndex, int syncTo);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void SetLayerType(int index, int type);

        public bool isAssetBundled { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; }
    }
}

